﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.IO;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using Microsoft.VisualBasic.FileIO;

namespace Folder_Control
{
    public partial class FolderControlForm : Form
    {
        #region Scroll Imports and Variables
        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        static public extern bool EnableScrollBar(System.IntPtr hWnd, uint wSBflags, uint wArrows);

        [DllImport("user32.dll")]
        static public extern bool ShowScrollBar(System.IntPtr hWnd, int wBar, bool bShow);

        private const uint SB_VERT = 1;
        private const uint ESB_DISABLE_BOTH = 0x3;
        private const uint ESB_ENABLE_BOTH = 0x0;
        private const int WM_VSCROLL = 0x115;

        Timer ScrollUpTimer;
        Timer ScrollDownTimer;

        #endregion

        private string initialPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
        private Item currentItem;
        private Stack<Item> previousPathStack = new Stack<Item>();
        private Stack<Item> forwardPathStack = new Stack<Item>();
        private FileSystemWatcher currentFolderWatcher;

        private ImageButton copyButton;
        private ImageButton moveButton;
        private ImageButton selectButton;
        private List<Item> selectItems = new List<Item>();

        public FolderControlForm()
        {
            InitializeComponent();
            InitializeTimers();

            SetUpButtons();

            backButton.Enabled = false;
            forwardButton.Enabled = false;

            currentItem = new Folder(initialPath, null);

            List<Item> items = ((Folder)currentItem).ListItemsInFolder();

            PopulateListView(items);
            pathTextBox.Text = currentItem.Path;

            PopulateImportantPlaces();

            SetUpCurrentFolderWatcher();

            // Disables vertical scroll bar           
            //EnableScrollBar(iconListView.Handle, (int)SB_VERT, ESB_DISABLE_BOTH);
            //ShowScrollBar(iconListView.Handle, (int)SB_VERT, true);
        }

        private void SetUpButtons()
        {
            copyButton = new ImageButton("copy", false);
            copyButton.Location = new Point(7, 88);
            copyButton.Size = new System.Drawing.Size(128, 32);
            copyButton.MouseUp += new MouseEventHandler(copyButtonAndMoveButton_MouseUp);
            mainPanel.Controls.Add(copyButton);

            moveButton = new ImageButton("move", false);
            moveButton.Location = new Point(mainPanel.Width - 128 - 10, 88);
            moveButton.Size = new System.Drawing.Size(128, 32);
            moveButton.MouseUp += new MouseEventHandler(copyButtonAndMoveButton_MouseUp);
            mainPanel.Controls.Add(moveButton);

            selectButton = new ImageButton("select", false);
            selectButton.Location = new Point(mainPanel.Width / 2 - 64, 88);
            selectButton.Size = new System.Drawing.Size(128, 32);
            selectButton.MouseUp += new MouseEventHandler(selectButton_MouseUp);
            mainPanel.Controls.Add(selectButton);
        }

        private void PopulateListView(List<Item> items)
        {
            iconList.Images.Clear();
            iconListView.Items.Clear();

            iconList.Images.AddRange(items.Select(x => x.Icon.ToBitmap()).ToArray());

            iconListView.LargeImageList = iconList;

            for (int i = 0; i < this.iconList.Images.Count; i++)
            {
                ListViewItem listItem = new ListViewItem();
                listItem.ImageIndex = i;
                listItem.Text = items[i].Name;
                listItem.Tag = items[i];
                iconListView.Items.Add(listItem);
            }
        }

        private void PopulateImportantPlaces()
        {
            List<Item> specialFolderList = SpecialFolders.SpecialFoldersForTreeViewDictionary.Values.ToList();

            smallIconList.Images.AddRange(specialFolderList.Select(x => x.Icon.ToBitmap()).ToArray());

            importantPlacesTreeNode.ImageList = smallIconList;

            for (int i = 0; i < specialFolderList.Count(); i++)
            {
                TreeNode treeNode = new TreeNode(specialFolderList[i].Name, i, i);
                treeNode.Tag = specialFolderList[i];
                importantPlacesTreeNode.Nodes.Add(treeNode);
            }
        }

        #region Form Resize
        private void mainSplitter_SplitterMoved(object sender, SplitterEventArgs e)
        {
            FormResize();
        }

        private void Form1_Resize(object sender, EventArgs e)
        {
            FormResize();
        }

        private void FormResize()
        {
            int formY = this.Size.Height;
            int formX = this.Size.Width;

            scrollUpButton.Size = new System.Drawing.Size(formX - importantPlacesTreeNode.Width - 30, scrollDownButton.Size.Height);

            scrollDownButton.Location = new Point(scrollDownButton.Location.X, formY - 87);
            scrollDownButton.Size = new System.Drawing.Size(formX - importantPlacesTreeNode.Width - 30, scrollDownButton.Size.Height);

            iconListView.Size = new System.Drawing.Size(formX - importantPlacesTreeNode.Width - 30, formY - 219);

            importantPlacesTreeNode.Size = new System.Drawing.Size(importantPlacesTreeNode.Width, formY - 45);

            if (mainPanel.Width > 132 * 3)
            { 
                selectButton.Location = new Point(mainPanel.Width / 2 - 64, 88);
                moveButton.Location = new Point(mainPanel.Width - 128 - 10, 88);
            }

            pathTextBox.Size = new System.Drawing.Size(formX - importantPlacesTreeNode.Width - pathTextBox.Location.X - 6 - backButton.Width - 23, pathTextBox.Height);

            forwardButton.Location = new Point(pathTextBox.Location.X + pathTextBox.Width + 6, forwardButton.Location.Y);

            goButton.Location = new Point(pathTextBox.Location.X + pathTextBox.Width / 2 - goButton.Width / 2, goButton.Location.Y);
        }
        #endregion

        #region Scroll Methods
        private void InitializeTimers()
        {
            ScrollUpTimer = new Timer();
            ScrollUpTimer.Interval = 150;
            ScrollUpTimer.Tick += new EventHandler(ScrollUpTimer_Tick);
            ScrollDownTimer = new Timer();
            ScrollDownTimer.Interval = 150;
            ScrollDownTimer.Tick += new EventHandler(ScrollDownTimer_Tick);
        }

        private void scrollUpButton_Click(object sender, EventArgs e)
        {
            SendMessage(iconListView.Handle, (uint)WM_VSCROLL, (System.UIntPtr)ScrollEventType.First, (System.IntPtr)0);
        }

        private void scrollUpButton_MouseEnter(object sender, EventArgs e)
        {
            ScrollUpTimer.Start();
        }

        private void scrollUpButton_MouseLeave(object sender, EventArgs e)
        {
            ScrollUpTimer.Stop();
        }

        private void scrollUpButton_DragEnter(object sender, DragEventArgs e)
        {
            ScrollUpTimer.Start();
        }

        private void scrollUpButton_DragLeave(object sender, EventArgs e)
        {
            ScrollUpTimer.Stop();
        }

        private void ScrollUpTimer_Tick(object sender, EventArgs args)
        {
            SendMessage(iconListView.Handle, (uint)WM_VSCROLL, (System.UIntPtr)ScrollEventType.SmallDecrement, (System.IntPtr)0);
        }

        private void scrollDownButton_Click(object sender, EventArgs e)
        {
            SendMessage(iconListView.Handle, (uint)WM_VSCROLL, (System.UIntPtr)ScrollEventType.Last, (System.IntPtr)0);
        }
        private void scrollDownButton_MouseEnter(object sender, EventArgs e)
        {
            ScrollDownTimer.Start();
        }

        private void scrollDownButton_MouseLeave(object sender, EventArgs e)
        {
            ScrollDownTimer.Stop();
        }

        private void scrollDownButton_DragEnter(object sender, DragEventArgs e)
        {
            ScrollDownTimer.Start();
        }

        private void scrollDownButton_DragLeave(object sender, EventArgs e)
        {
            ScrollDownTimer.Stop();
        }

        private void ScrollDownTimer_Tick(object sender, EventArgs args)
        {
            SendMessage(iconListView.Handle, (uint)WM_VSCROLL, (System.UIntPtr)ScrollEventType.SmallIncrement, (System.IntPtr)0);
        }
        #endregion

        #region Current Folder Watcher Methods
        // Sets up a file watcher to watch for changes in the current folder
        private void SetUpCurrentFolderWatcher()
        {
            // Is not a special folder
            if (currentItem.Type != ItemType.SpecialFolder)
            {
                currentFolderWatcher = new FileSystemWatcher();
                currentFolderWatcher.Path = currentItem.Path;
                currentFolderWatcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
                currentFolderWatcher.Changed += new FileSystemEventHandler(currentFolderWatcher_Changed);
                currentFolderWatcher.Deleted += new FileSystemEventHandler(currentFolderWatcher_Changed);
                currentFolderWatcher.EnableRaisingEvents = true;
            }
        }

        // Refreshes current folder when it is changed
        private void currentFolderWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            // Must be invoked because watcher runs on a different thread than form
            iconListView.Invoke(new MethodInvoker(RefreshFolder));
            itemDragList.Clear();
        }
        #endregion

        // Double Click iconListView
        private void iconListView_DoubleClick(object sender, EventArgs e)
        {
            Point mousePosition = Control.MousePosition;
            Point listPoint = iconListView.PointToClient(mousePosition);

            // Gets the item that was hit (if an item was hit)
            ListViewHitTestInfo itemHitInfo = iconListView.HitTest(listPoint.X, listPoint.Y);

            // Check to see if an item was clicked on
            if (itemHitInfo.Item != null)
            {
                Item item = (Item)(itemHitInfo.Item.Tag);

                // item is anything but a File (or LinkFile)
                if (!(item is File || item is ErrorItem))
                {
                    // Clear lists
                    iconList.Images.Clear();
                    iconListView.Items.Clear();
                    Cursor.Current = Cursors.WaitCursor;
                    iconListView.Refresh();
                }

                // Perform on click (Folders and SpecialFolders return new items, Files do not)
                List<Item> newItems = item.onClick();

                if (newItems != null) // if there were new items to return (Meaning item is a folder or special folder)
                {
                    NavigateToFolder(item, newItems);
                }
                Cursor.Current = Cursors.Arrow;
            }
        }

        // Single Click importantPlacesTreeNode
        private void importantPlacesTreeNode_Click(object sender, EventArgs e)
        {
            Point mousePosition = Control.MousePosition;
            Point treePoint = importantPlacesTreeNode.PointToClient(mousePosition);

            // Gets the item that was hit (if an item was hit)
            TreeViewHitTestInfo itemHitInfo = importantPlacesTreeNode.HitTest(treePoint.X, treePoint.Y);

            // Check to see if an item was clicked on
            if (itemHitInfo.Node != null)
            {
                Item item = (Item)(itemHitInfo.Node.Tag);

                // item is anything but a File (or LinkFile)
                if (!(item is File))
                {
                    // Clear lists
                    iconList.Images.Clear();
                    iconListView.Items.Clear();
                    Cursor.Current = Cursors.WaitCursor;
                    iconListView.Refresh();
                }

                // Perform on click (Folders and SpecialFolders return new items, Files do not)
                List<Item> newItems = item.onClick();

                if (newItems != null) // if there were new items to return (Meaning item is a folder or special folder)
                {
                    NavigateToFolder(item, newItems);
                }
                Cursor.Current = Cursors.Arrow;
            }
        }

        private void NavigateToFolder(Item item, List<Item> newItems)
        {
            previousPathStack.Push(currentItem); // push the current path for back tracking
            backButton.Enabled = true;
            forwardPathStack.Clear(); // clear the forward path
            forwardButton.Enabled = false; // disable the forward button
            currentItem = item;
            PopulateListView(newItems);
            pathTextBox.Text = item.Path;
            SetUpCurrentFolderWatcher();
            selectButton.isActive = false; // set to inactive state because noting is selected
        }

        private void RefreshFolder()
        {
            if (currentItem.Type != ItemType.SpecialFolder)
            {
                // Clear lists
                iconList.Images.Clear();
                iconListView.Items.Clear();

                PopulateListView(((Folder)currentItem).ListItemsInFolder());
            }
        }

        private void backButton_MouseUp(object sender, MouseEventArgs e)
        {
            if (previousPathStack.Count > 0)
            {
                forwardPathStack.Push(currentItem); // push the current item onto the forward stack
                forwardButton.Enabled = true;

                currentItem = previousPathStack.Pop(); // pop the previous path off the stack to the current path

                if (previousPathStack.Count() == 0)
                    backButton.Enabled = false;

                List<Item> items = currentItem.Type == ItemType.SpecialFolder
                                    ? ((SpecialFolder)currentItem).GetItems()
                                    : ((Folder)currentItem).ListItemsInFolder();

                PopulateListView(items);
                pathTextBox.Text = currentItem.Path;
            }
        }

        private void forwardButton_MouseUp(object sender, MouseEventArgs e)
        {
            if (forwardPathStack.Count > 0)
            {              
                previousPathStack.Push(currentItem); // push the current item onto the previous stack
                backButton.Enabled = true;

                currentItem = forwardPathStack.Pop(); // pop the forward path off the stack to the current path

                if (forwardPathStack.Count() == 0)
                    forwardButton.Enabled = false;

                List<Item> items = currentItem.Type == ItemType.SpecialFolder
                                    ? ((SpecialFolder)currentItem).GetItems()
                                    : ((Folder)currentItem).ListItemsInFolder();

                PopulateListView(items);
                pathTextBox.Text = currentItem.Path;
            }
        }

        private void goButton_Click(object sender, EventArgs e)
        {
            GoToEnteredPath();
        }

        private void pathTextBox_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                GoToEnteredPath();
            }
        }

        // Go to the path in pathTextBox
        private void GoToEnteredPath()
        {
            string path = pathTextBox.Text;

            if (Directory.Exists(path))
            {
                Folder item = new Folder(path, null);
                NavigateToFolder(item, item.ListItemsInFolder());
            }
            else if (System.IO.File.Exists(path))
            {
                // if path is a file open the file with explorer.exe
                File item = new File(path, null);
                item.onClick();
            }
            else
            {
                MessageBox.Show("Path does not exist.");
            }
        }

        #region Item Drag Methods

        private List<ListViewItem> itemDragList = new List<ListViewItem>();

        // Occurs when an item in the iconListView is being dragged
        private void iconListView_ItemDrag(object sender, ItemDragEventArgs e)
        {
            // Can't drag items to my computer
            if (currentItem is MyComputer)
                return;

            itemDragList.Clear();
            List<string> itemPathList = new List<string>();
            foreach (ListViewItem listViewItem in iconListView.SelectedItems)
            {
                itemDragList.Add(listViewItem);
                itemPathList.Add((listViewItem.Tag is Link)
                                    ? ((Link)listViewItem.Tag).LinkPath
                                    : ((Item)listViewItem.Tag).Path);
            }

            DataObject data = new DataObject(DataFormats.FileDrop, itemPathList.ToArray());
            data.SetData(DataFormats.StringFormat, itemPathList.ToArray());
            iconListView.DoDragDrop(data, DragDropEffects.Move);
        }

        private void iconListView_DragDrop(object sender, DragEventArgs e)
        {
            Point itemPoint = iconListView.PointToClient(new Point(e.X, e.Y));
            ListViewItem dragToListViewItem = iconListView.GetItemAt(itemPoint.X, itemPoint.Y);

            // if itemDragList contains items and item was dragged over an listViewItem
            if (itemDragList.Count > 0 && dragToListViewItem != null)
            {
                Item dragToItem = (Item)dragToListViewItem.Tag;

                // Uses variable itemDragList defined in function iconListView_ItemDrag
                foreach (ListViewItem listViewItem in itemDragList)
                {
                    Item dragItem = (Item)listViewItem.Tag;

                    if (dragItem != null && dragToItem != null)
                    {
                        MoveDragItem(dragToItem, dragItem, listViewItem);
                    }
                }               
            }
            // itemDragList.Count == 0 indicates it was dragged from outside of the form
            else if (e.Data.GetDataPresent(DataFormats.FileDrop) && itemDragList.Count == 0) 
            {
                Item dragToItem = dragToListViewItem != null ? (Item)dragToListViewItem.Tag : currentItem;

                List<Item> itemsDraggedIn = ToItemList(((string[])e.Data.GetData(DataFormats.FileDrop)).ToList());

                foreach (Item dragItem in itemsDraggedIn)
                {
                    if (dragItem != null && dragToItem != null)
                    {
                        MoveDragItem(dragToItem, dragItem, null);
                    }
                }
            }
            itemDragList.Clear();
        }

        private List<Item> ToItemList(List<string> filePaths)
        {
            List<Item> itemList = new List<Item>();
            foreach (string filePath in filePaths)
            {
                if (System.IO.File.Exists(filePath))
                {
                    FileInfo fileInfo = new FileInfo(filePath);

                    itemList.Add(fileInfo.Extension.Equals(".lnk") 
                                    ? LinkFactory.GetLink(fileInfo.Name, filePath, null)
                                    : new File(filePath, null));
                }
                else if (Directory.Exists(filePath))
                {
                    itemList.Add(new Folder(filePath, null));
                }
            }

            return itemList;
        }

        private void importantPlacesTreeNode_DragDrop(object sender, DragEventArgs e)
        {
            Point nodePoint = importantPlacesTreeNode.PointToClient(new Point(e.X, e.Y));
            TreeNode dragToNode = importantPlacesTreeNode.GetNodeAt(nodePoint.X, nodePoint.Y);

            // if itemDragList contains items and item was dragged over a dragToNode
            if (itemDragList.Count > 0 && dragToNode != null)
            {        
                Item dragToItem = (Item)dragToNode.Tag;

                // Uses variable itemDragList defined in function iconListView_ItemDrag
                foreach (ListViewItem listViewItem in itemDragList)
                {
                    Item dragItem = (Item)listViewItem.Tag;

                    if (dragItem != null && dragToItem != null)
                    {
                        MoveDragItem(dragToItem, dragItem, listViewItem);
                    }
                }
                
            }
            // itemDragList.Count == 0 indicates it was dragged from outside of the form
            else if (e.Data.GetDataPresent(DataFormats.FileDrop) && itemDragList.Count == 0)
            {
                Item dragToItem = dragToNode != null ? (Item)dragToNode.Tag : currentItem;

                List<Item> itemsDraggedIn = ToItemList(((string[])e.Data.GetData(DataFormats.FileDrop)).ToList());

                foreach (Item dragItem in itemsDraggedIn)
                {
                    if (dragItem != null && dragToItem != null)
                    {
                        MoveDragItem(dragToItem, dragItem, null);
                    }
                }
            }
            itemDragList.Clear();
        }

        private void backButton_DragDrop(object sender, DragEventArgs e)
        {
            if (previousPathStack.Count > 0 && itemDragList.Count > 0)
            {
                // Uses variable itemDragList defined in function iconListView_ItemDrag
                foreach (ListViewItem listViewItem in itemDragList)
                {
                    Item dragItem = (Item)listViewItem.Tag;

                    if (dragItem != null)
                    {
                        MoveDragItem(previousPathStack.Peek(), dragItem, listViewItem);
                    }
                }
            }
            // itemDragList.Count == 0 indicates it was dragged from outside of the form
            else if (e.Data.GetDataPresent(DataFormats.FileDrop) && itemDragList.Count == 0)
            {
                List<Item> itemsDraggedIn = ToItemList(((string[])e.Data.GetData(DataFormats.FileDrop)).ToList());
                foreach (Item dragItem in itemsDraggedIn)
                {
                    if (dragItem != null)
                        MoveDragItem(previousPathStack.Peek(), dragItem, null);  
                }
            }
            itemDragList.Clear();
        }

        private void forwardButton_DragDrop(object sender, DragEventArgs e)
        {
            if (forwardPathStack.Count > 0 && itemDragList.Count > 0)
            {
                // Uses variable itemDragList defined in function iconListView_ItemDrag
                foreach (ListViewItem listViewItem in itemDragList)
                {
                    Item dragItem = (Item)listViewItem.Tag;

                    if (dragItem != null)
                    {
                        MoveDragItem(forwardPathStack.Peek(), dragItem, listViewItem);
                    }
                }
            }
            // itemDragList.Count == 0 indicates it was dragged from outside of the form
            else if (e.Data.GetDataPresent(DataFormats.FileDrop) && itemDragList.Count == 0)
            {
                List<Item> itemsDraggedIn = ToItemList(((string[])e.Data.GetData(DataFormats.FileDrop)).ToList());
                foreach (Item dragItem in itemsDraggedIn)
                {
                    if (dragItem != null)
                        MoveDragItem(forwardPathStack.Peek(), dragItem, null);
                }
            }
            itemDragList.Clear();
        }

        // DragEnter for iconListView, importantPlacesTreeNode, backButton, and forwardButton
        private void items_DragEnter(object sender, DragEventArgs e)
        {
            if (itemDragList.Count > 0 || e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Move;
        }

        // Moves the item being dragged to the specified folder (Or deletes if dragged to is the Recycle Bin)
        private void MoveDragItem(Item dragToItem, Item dragItem, ListViewItem listViewItem)
        {
            // Return if equal
            if (DetermineIfEqualPaths(dragToItem, dragItem))
                return;
                
            try
            {
                // Move item, delete from iconListView if move is successful
                if (dragItem.Type == ItemType.Link)
                {
                    if(MoveLink(dragToItem, dragItem))
                        iconListView.Items.Remove(listViewItem);
                }
                else if (dragItem.Type == ItemType.File)
                {
                    if (MoveFile(dragToItem, dragItem))
                        iconListView.Items.Remove(listViewItem);
                }
                else if (dragItem.Type == ItemType.Folder)
                {
                    if (MoveFolder(dragToItem, dragItem))
                        iconListView.Items.Remove(listViewItem);
                }
            }
            catch (IOException e)
            {
                MessageBox.Show(e.Message);
            }

        }

        
        #region Draw Icon on Drag (Not Currently Used)
        /*
        #region Icon Drag Variables
        private Form mouseForm = new Form { TopMost = true, FormBorderStyle = System.Windows.Forms.FormBorderStyle.None, Width = 48, Height = 48 };
        private Bitmap mouseIcon;
        private Timer mouseTimer = new Timer { Interval = 5 };
        #endregion

        private void iconListView_ItemDrag(object sender, ItemDragEventArgs e)
        {
            mouseForm.Paint += new PaintEventHandler(mouseForm_Paint);
            mouseForm.TransparencyKey = mouseForm.BackColor;

            Point mousePosition = Control.MousePosition;
            mouseForm.Location = new Point(mousePosition.X, mousePosition.Y);

            mouseForm.Show();

            mouseIcon = ((Item)(((ListViewItem)(e.Item)).Tag)).Icon.ToBitmap();

            mouseTimer.Tick += new EventHandler(mouseTimer_Tick);
            mouseTimer.Start();
            

            iconListView.DoDragDrop(e.Item, DragDropEffects.Move);   
        }

        // Sets the location of the form containing the dragged icon
        // Also determines if item has left form
        private void mouseTimer_Tick(object sender, EventArgs e)
        {
            Point mousePosition = Control.MousePosition;
            Point listPoint = this.PointToScreen(new Point(0, 0));

            if (mousePosition.X > listPoint.X + this.Width || mousePosition.X < listPoint.X
                || mousePosition.Y > listPoint.Y + this.Height || mousePosition.Y < listPoint.Y)
            {
                mouseForm.Hide();
            }
            else
            {
                mouseForm.Show();
                mouseForm.Location = new Point(mousePosition.X, mousePosition.Y);
            }
        }

        // Paints the transparent drag icon
        private void mouseForm_Paint(object sender, PaintEventArgs e)
        {
            Graphics graphics = mouseForm.CreateGraphics();
            graphics.Clear(mouseForm.BackColor);

            ImageAttributes attributes = new ImageAttributes();

            attributes.SetColorMatrix(new ColorMatrix { Matrix33 = 0.8f }, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

            graphics.DrawImage(mouseIcon, new Rectangle(1, 1, mouseIcon.Width - 2, mouseIcon.Height - 2), 0, 0,
                                mouseIcon.Width, mouseIcon.Height, GraphicsUnit.Pixel, attributes);
        }
        
        private void StopIconDrag()
        {
            mouseTimer.Stop();
            mouseForm.Hide();
        } 

        */
        #endregion
        #endregion

        #region Copy, Move, and Select buttons

        private void selectButton_MouseUp(object sender, MouseEventArgs e)
        {
            if (iconListView.SelectedItems.Count > 0)
            {
                copyButton.isActive = true;
                moveButton.isActive = true;

                selectItems.Clear();
                for(int i = 0; i < iconListView.SelectedItems.Count; i++)
                {
                    selectItems.Add((Item)iconListView.SelectedItems[i].Tag);
                }
            }
        }

        private void copyButtonAndMoveButton_MouseUp(object sender, MouseEventArgs e)
        {
            Item toItem = currentItem;
            bool isCopy = ((ImageButton)sender).BaseName == "copy";
            bool copied = false;
            bool moved = false;

            foreach (Item item in selectItems)
            {
                // Return if equal
                if (DetermineIfEqualPaths(toItem, item))
                    continue;

                try
                {
                    if (item.Type == ItemType.Link)
                    {
                        if (isCopy)
                            copied = CopyLink(toItem, item);
                        else // move
                            moved = MoveLink(toItem, item);
                    }
                    else if (item.Type == ItemType.File)
                    {
                        if (isCopy)
                            copied = CopyFile(toItem, item);
                        else // move
                            moved = MoveFile(toItem, item);
                    }
                    else if (item.Type == ItemType.Folder)
                    {
                        if (isCopy)
                            copied = CopyFolder(toItem, item);
                        else // move
                            moved = MoveFolder(toItem, item);             
                    }
                }
                catch (IOException ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }

            if (moved)
            {
                selectItems.Clear();
                moveButton.isActive = false;
                copyButton.isActive = false;
            }

            if (moved || copied)
            {
                RefreshFolder();
                selectButton.isActive = false;
            }
        }

        private void iconListView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            if (iconListView.SelectedItems.Count > 0)
            {
                selectButton.isActive = true;
            }
            else
            {
                selectButton.isActive = false;
            }
        }

        private void iconListView_Leave(object sender, EventArgs e)
        {
            selectButton.isActive = false;
        }

        #endregion

        #region Move and Copy Methods

        private bool DetermineIfEqualPaths(Item dragToItem, Item dragItem)
        {
            bool equalPath = false;

            if (dragItem.Path == dragToItem.Path)
            {
                if (dragItem.Type != ItemType.Link && dragToItem.Type != ItemType.Link)
                    equalPath = true;
                else if (dragItem.Type == ItemType.Link && dragToItem.Type == ItemType.Link)
                {
                    if (((Link)dragItem).LinkPath == ((Link)dragToItem).LinkPath)
                        equalPath = true;
                }
                else if (dragItem.Type == ItemType.Link)
                {
                    if (((Link)dragItem).LinkPath == dragToItem.Path)
                        equalPath = true;
                }
                else if (dragToItem.Type == ItemType.Link)
                {
                    if (dragItem.Path == ((Link)dragToItem).LinkPath)
                        equalPath = true;
                }
            }

            if (equalPath)
                MessageBox.Show("Cannot move " + dragItem.Name + ", same path as destination.");

            return equalPath;
        }

        private bool MoveLink(Item dragToItem, Item dragItem)
        {
            if (dragToItem is Folder)
            {
                if (!System.IO.File.Exists(dragToItem.Path + @"\" + dragItem.Name + ".lnk"))
                {
                    FileSystem.MoveFile(((Link)dragItem).LinkPath, dragToItem.Path + @"\" + dragItem.Name + ".lnk");
                    return true;
                }
                else
                {
                    MessageBox.Show("Cannot move " + dragItem.Name + ", file already exists at destination.");
                    return false;
                }
            }
            else if (dragToItem is RecycleBin)
            {
                FileSystem.DeleteFile(((Link)dragItem).LinkPath, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
                return true;
            }
            return false;
        }

        private bool MoveFile(Item dragToItem, Item dragItem)
        {
            if (dragToItem is Folder)
            {
                if (!System.IO.File.Exists(dragToItem.Path + @"\" + dragItem.Name))
                {
                    FileSystem.MoveFile(dragItem.Path, dragToItem.Path + @"\" + dragItem.Name);
                    return true;
                }
                else
                {
                    MessageBox.Show("Cannot move " + dragItem.Name + ", file already exists at destination.");
                    return false;
                }
            }
            else if (dragToItem is RecycleBin)
            {
                FileSystem.DeleteFile(dragItem.Path, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
                return true;
            }
            return false;
        }

        private bool MoveFolder(Item dragToItem, Item dragItem)
        {
            if (dragToItem is Folder)
            {
                if (!System.IO.Directory.Exists(dragToItem.Path + @"\" + dragItem.Name))
                {
                    FileSystem.MoveDirectory(dragItem.Path, dragToItem.Path + @"\" + dragItem.Name);
                    return true;
                }
                else
                {
                    MessageBox.Show("Cannot move " + dragItem.Name + ", folder already exists at destination.");
                    return false;
                }
            }
            else if (dragToItem is RecycleBin)
            {
                FileSystem.DeleteDirectory(dragItem.Path, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
                return true;
            }
            return false;
        }

        private bool CopyFolder(Item toItem, Item item)
        {
            if (toItem is Folder)
            {
                if (!System.IO.Directory.Exists(toItem.Path + @"\" + item.Name))
                {
                    FileSystem.CopyDirectory(item.Path, toItem.Path + @"\" + item.Name);
                    return true;
                }
                else
                {
                    MessageBox.Show("Cannot copy " + item.Name + ", folder already exists at destination.");
                    return false;
                }
            }
            return false;
        }

        private bool CopyFile(Item toItem, Item item)
        {
            if (toItem is Folder)
            {
                if (!System.IO.File.Exists(toItem.Path + @"\" + item.Name))
                {
                    FileSystem.CopyFile(item.Path, toItem.Path + @"\" + item.Name);
                    return true;
                }
                else
                {
                    MessageBox.Show("Cannot copy " + item.Name + ", file already exists at destination.");
                    return false;
                }
            }
            return false;
        }

        private bool CopyLink(Item toItem, Item item)
        {
            if (toItem is Folder)
            {
                if (!System.IO.File.Exists(toItem.Path + @"\" + item.Name + ".lnk"))
                {
                    FileSystem.CopyFile(((Link)item).LinkPath, toItem.Path + @"\" + item.Name + ".lnk");
                    return true;
                }
                else
                {
                    MessageBox.Show("Cannot copy " + item.Name + ", file already exists at destination.");
                    return false;
                }
            }
            return false;
        }
        #endregion
    }
}
